using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Serialization;
using jQueryApi;

namespace SyncJS
{
    [Imported]
    public class SyncInfoJS
    {
        [PreserveCase]
        public string Name;
        [PreserveCase]
        public Date LDate;
        [PreserveCase]
        public Date RDate;
        [PreserveCase]
        public UInt64 LSize;
        [PreserveCase]
        public UInt64 RSize;
        [PreserveCase]
        public int SizeDelta;
        [PreserveCase]
        public bool Upload;
        [PreserveCase]
        public bool Download;
        [PreserveCase]
        public bool Transfer;
        [PreserveCase]
        public bool Transfered;
    }

    internal static class SyncList
    {
        private static int _uploadCnt;
        private static int _downloadCnt;
        private static int _noneCnt;

        private const string UploadId = "#SyncUpList";
        private const string DownloadId = "#SyncDownList";
        private const string NoneId = "#SyncNoneList";
        private const string LogId = "#SyncLog";
        private const string InfoItemClass = "InfoItemClass";
        private const string InfoNameClass = "InfoNameClass";

        private static Dictionary<string, SyncInfoJS> _infos;

        private static bool _listsInitialized;

        public static void InitLists()
        {
            if (_listsInitialized)
                return;
            Script.Literal(@"Date.prototype.toJSON = function () {return ""/Date("" + this.getTime() + ""-0400)/""}");
            jQuery.Select("th input[type=checkbox]").Live("click",
                delegate
                {
                    jQueryObject checkBoxes = jQuery.Select("input[type=checkbox]", jQuery.This.Closest("table"));
                    bool state = jQuery.This.GetAttribute("checked") == "checked";
                    if (!state)
                        checkBoxes.RemoveAttr("checked");
                    else
                        checkBoxes.Attribute("checked", (string)Script.Literal("true"));
                }
             );

            // Add "sync dates" button
            jQueryObject headEl = jQuery.Select(DownloadId).Closest("table").Find("th.head2");
            jQuery.FromHtml("<button/>").Html("sync dates").Click(
                delegate
                    {
                        string jsonInfo = InfoList;
                        Script.Literal("window.external.SyncDates({0})", jsonInfo);
                    }).CSS("float","right").PrependTo(headEl);
            _listsInitialized = true;
        }

        public static string InfoList
        {
            get
            {
                CaptureUI();
                return Dictify(_infos);
            }
        }

        public static void ClearLists()
        {
            jQuery.Select(UploadId + "," + DownloadId + "," + NoneId).Each(
                delegate
                    {
                        jQuery.This.Empty().Closest("table").Hide();
                    }
                );
        }

        public static void FillLists(SyncInfoJS[] infos)
        {
            _infos = ConvertToDict(infos);

            Counts = 0;
            foreach (KeyValuePair<string,SyncInfoJS> pair in _infos)
            {
                SyncInfoJS info = pair.Value;
                if (info.Upload)
                    AddUploadFile(info);
                if (info.Download)
                    AddDownloadFile(info);
                if (!info.Upload && !info.Download)
                    AddNoneFile(info);
            }

            if (_uploadCnt != 0)
                jQuery.Select(UploadId).Parent().Show();
            else
                jQuery.Select(UploadId).Parent().Hide();

            if (_downloadCnt != 0)
                jQuery.Select(DownloadId).Parent().Show();
            else
                jQuery.Select(DownloadId).Parent().Hide();

            if (_noneCnt != 0)
                jQuery.Select(NoneId).Parent().Show();
            else
                jQuery.Select(NoneId).Parent().Hide();

            string logText = (string)Script.Literal("window.external.LogText()");
            jQuery.Select(LogId).Html(logText);

            if ((bool)Script.Literal("window.external.AutoSync()"))
                Script.Literal("window.external.Sync()");

        }

        private static Dictionary<string, SyncInfoJS> ConvertToDict(SyncInfoJS[] infos)
        {
            Dictionary<string, SyncInfoJS> dict = new Dictionary<string, SyncInfoJS>();
            foreach (SyncInfoJS info in infos)
            {
                dict[info.Name] = info;
            }
            return dict;
        }

        private static int Counts
        {
            // ReSharper disable UnusedMember.Local
            get { return 0; }
            // ReSharper restore UnusedMember.Local
            set
            {
                _uploadCnt = _downloadCnt = _noneCnt = value;
            }
        }

        private static void AddUploadFile(SyncInfoJS info)
        {
            _uploadCnt++;
            jQueryObject tBody = jQuery.Select(UploadId);
            jQueryObject tRow = jQuery.FromHtml("<tr/>").AppendTo(tBody);
            FillTableRow(info, tRow);
            if (info.Upload)
                jQuery.Select("input[type=checkbox]", tRow).Attribute("checked", "true");
        }

        private static void AddDownloadFile(SyncInfoJS info)
        {
            _downloadCnt++;
            jQueryObject tBody = jQuery.Select(DownloadId);
            jQueryObject tRow = jQuery.FromHtml("<tr/>").AppendTo(tBody);
            FillTableRow(info, tRow);
            if (info.Download)
                jQuery.Select("input[type=checkbox]", tRow).Attribute("checked", "true");
        }

        private static void AddNoneFile(SyncInfoJS info)
        {
            _noneCnt++;
            jQueryObject tBody = jQuery.Select(NoneId);
            jQueryObject tRow = jQuery.FromHtml("<tr/>").AppendTo(tBody);
            FillTableRow(info, tRow);
        }

        private static void FillTableRow(SyncInfoJS info, jQueryObject tRow)
        {
            tRow.AddClass(InfoItemClass);
            Date lDate = new Date(info.LDate.GetTime());
            Date rDate = new Date(info.RDate.GetTime());
            jQuery.FromHtml("<td/>").Html("<input type='checkbox'>").AppendTo(tRow);
            jQuery.FromHtml("<td/>").Html(info.Name).AddClass(InfoNameClass).AppendTo(tRow);
            jQuery.FromHtml("<td/>").Html(lDate.Format("yyyy-MM-dd HH:mm:ss")).AppendTo(tRow);
            jQuery.FromHtml("<td/>").Html(rDate.Format("yyyy-MM-dd HH:mm:ss")).AppendTo(tRow);
            jQuery.FromHtml("<td/>").Html(info.SizeDelta.ToString()).AppendTo(tRow);
        }

        private static void CaptureUI()
        {
            jQuery.Select("." + InfoItemClass).Each(
                delegate
                    {
                        string name = jQuery.Select("." + InfoNameClass, jQuery.This).GetHtml();
                        _infos[name].Transfer =
                            jQuery.Select("input[type=checkbox]", jQuery.This).GetAttribute("checked") == "checked";
                    });
        }

        private static string Dictify(Dictionary<string,SyncInfoJS> dict )
        {
            string ot = "[";
            int cnt = 0;
            foreach (KeyValuePair<string,SyncInfoJS> pair in dict)
            {
                if (cnt++ > 0)
                    ot += ",";
                ot += "{";
                ot += @"""Key"": " + Json.Stringify(pair.Key);
                ot += @", ""Value"": " + Json.Stringify(pair.Value);
                ot += "}";
            }
            ot += "]";
            return ot;
        }
    }
}
